//----------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2014 Tasharen Entertainment
//----------------------------------------------

using UnityEngine;

/// <summary>
/// This script can be used to stretch objects relative to the screen's width and height.
/// The most obvious use would be to create a full-screen background by attaching it to a sprite.
/// </summary>

[ExecuteInEditMode]
[AddComponentMenu("NGUI/UI/Stretch")]
public class UIStretch : MonoBehaviour
{
    public enum Style
    {
        None,
        Horizontal,
        Vertical,
        Both,
        BasedOnHeight,
        FillKeepingRatio, // Fits the image so that it entirely fills the specified container keeping its ratio
        FitInternalKeepingRatio // Fits the image/item inside of the specified container keeping its ratio
    }

    /// <summary>
    /// Camera used to determine the anchor bounds. Set automatically if none was specified.
    /// </summary>

    public Camera uiCamera = null;

    /// <summary>
    /// Object used to determine the container's bounds. Overwrites the camera-based anchoring if the value was specified.
    /// </summary>

    public GameObject container = null;

    /// <summary>
    /// Stretching style.
    /// </summary>

    public Style style = Style.None;

    /// <summary>
    /// Whether the operation will occur only once and the script will then be disabled.
    /// Screen size changes will still cause the script's logic to execute.
    /// </summary>

    public bool runOnlyOnce = true;

    /// <summary>
    /// Relative-to-target size.
    /// </summary>

    public Vector2 relativeSize = Vector2.one;

    /// <summary>
    /// The size that the item/image should start out initially.
    /// Used for FillKeepingRatio, and FitInternalKeepingRatio.
    /// Contributed by Dylan Ryan.
    /// </summary>

    public Vector2 initialSize = Vector2.one;

    /// <summary>
    /// Padding applied after the size of the stretched object gets calculated. This value is in pixels.
    /// </summary>

    public Vector2 borderPadding = Vector2.zero;

    // Deprecated legacy functionality
    [HideInInspector]
    [SerializeField]
    UIWidget widgetContainer;

    Transform mTrans;
    UIWidget mWidget;
    UISprite mSprite;
    UIPanel mPanel;
    UIRoot mRoot;
    Animation mAnim;
    Rect mRect;
    bool mStarted = false;

    void Awake()
    {
        mAnim = GetComponent<Animation>();
        mRect = new Rect();
        mTrans = transform;
        mWidget = GetComponent<UIWidget>();
        mSprite = GetComponent<UISprite>();
        mPanel = GetComponent<UIPanel>();

        UICamera.onScreenResize += ScreenSizeChanged;
    }

    void OnDestroy() { UICamera.onScreenResize -= ScreenSizeChanged; }

    void ScreenSizeChanged() { if (mStarted && runOnlyOnce) Update(); }

    void Start()
    {
        if (container == null && widgetContainer != null)
        {
            container = widgetContainer.gameObject;
            widgetContainer = null;
#if UNITY_EDITOR
            NGUITools.SetDirty(this);
#endif
        }

        if (uiCamera == null) uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);
        mRoot = NGUITools.FindInParents<UIRoot>(gameObject);

        Update();

        mStarted = true;
    }

    void Update()
    {
        if (mAnim != null && mAnim.isPlaying) return;

        if (style != Style.None)
        {
            UIWidget wc = (container == null) ? null : container.GetComponent<UIWidget>();
            UIPanel pc = (container == null && wc == null) ? null : container.GetComponent<UIPanel>();
            float adjustment = 1f;

            if (wc != null)
            {
                Bounds b = wc.CalculateBounds(transform.parent);

                mRect.x = b.min.x;
                mRect.y = b.min.y;

                mRect.width = b.size.x;
                mRect.height = b.size.y;
            }
            else if (pc != null)
            {
                if (pc.clipping == UIDrawCall.Clipping.None)
                {
                    // Panel has no clipping -- just use the screen's dimensions
                    float ratio = (mRoot != null) ? (float)mRoot.activeHeight / Screen.height * 0.5f : 0.5f;
                    mRect.xMin = -Screen.width * ratio;
                    mRect.yMin = -Screen.height * ratio;
                    mRect.xMax = -mRect.xMin;
                    mRect.yMax = -mRect.yMin;
                }
                else
                {
                    // Panel has clipping -- use it as the mRect
                    Vector4 cr = pc.finalClipRegion;
                    mRect.x = cr.x - (cr.z * 0.5f);
                    mRect.y = cr.y - (cr.w * 0.5f);
                    mRect.width = cr.z;
                    mRect.height = cr.w;
                }
            }
            else if (container != null)
            {
                Transform root = transform.parent;
                Bounds b = (root != null) ? NGUIMath.CalculateRelativeWidgetBounds(root, container.transform) :
                    NGUIMath.CalculateRelativeWidgetBounds(container.transform);

                mRect.x = b.min.x;
                mRect.y = b.min.y;

                mRect.width = b.size.x;
                mRect.height = b.size.y;
            }
            else if (uiCamera != null)
            {
                mRect = uiCamera.pixelRect;
                if (mRoot != null) adjustment = mRoot.pixelSizeAdjustment;
            }
            else return;

            float rectWidth = mRect.width;
            float rectHeight = mRect.height;

            if (adjustment != 1f && rectHeight > 1f)
            {
                float scale = mRoot.activeHeight / rectHeight;
                rectWidth *= scale;
                rectHeight *= scale;
            }

            Vector3 size = (mWidget != null) ? new Vector3(mWidget.width, mWidget.height) : mTrans.localScale;

            if (style == Style.BasedOnHeight)
            {
                size.x = relativeSize.x * rectHeight;
                size.y = relativeSize.y * rectHeight;
            }
            else if (style == Style.FillKeepingRatio)
            {
                // Contributed by Dylan Ryan
                float screenRatio = rectWidth / rectHeight;
                float imageRatio = initialSize.x / initialSize.y;

                if (imageRatio < screenRatio)
                {
                    // Fit horizontally
                    float scale = rectWidth / initialSize.x;
                    size.x = rectWidth;
                    size.y = initialSize.y * scale;
                }
                else
                {
                    // Fit vertically
                    float scale = rectHeight / initialSize.y;
                    size.x = initialSize.x * scale;
                    size.y = rectHeight;
                }
            }
            else if (style == Style.FitInternalKeepingRatio)
            {
                // Contributed by Dylan Ryan
                float screenRatio = rectWidth / rectHeight;
                float imageRatio = initialSize.x / initialSize.y;

                if (imageRatio > screenRatio)
                {
                    // Fit horizontally
                    float scale = rectWidth / initialSize.x;
                    size.x = rectWidth;
                    size.y = initialSize.y * scale;
                }
                else
                {
                    // Fit vertically
                    float scale = rectHeight / initialSize.y;
                    size.x = initialSize.x * scale;
                    size.y = rectHeight;
                }
            }
            else
            {
                if (style != Style.Vertical)
                    size.x = relativeSize.x * rectWidth;

                if (style != Style.Horizontal)
                    size.y = relativeSize.y * rectHeight;
            }

            if (mSprite != null)
            {
                float multiplier = (mSprite.atlas != null) ? mSprite.atlas.pixelSize : 1f;
                size.x -= borderPadding.x * multiplier;
                size.y -= borderPadding.y * multiplier;

                if (style != Style.Vertical)
                    mSprite.width = Mathf.RoundToInt(size.x);

                if (style != Style.Horizontal)
                    mSprite.height = Mathf.RoundToInt(size.y);

                size = Vector3.one;
            }
            else if (mWidget != null)
            {
                if (style != Style.Vertical)
                    mWidget.width = Mathf.RoundToInt(size.x - borderPadding.x);

                if (style != Style.Horizontal)
                    mWidget.height = Mathf.RoundToInt(size.y - borderPadding.y);

                size = Vector3.one;
            }
            else if (mPanel != null)
            {
                Vector4 cr = mPanel.baseClipRegion;

                if (style != Style.Vertical)
                    cr.z = size.x - borderPadding.x;

                if (style != Style.Horizontal)
                    cr.w = size.y - borderPadding.y;

                mPanel.baseClipRegion = cr;
                size = Vector3.one;
            }
            else
            {
                if (style != Style.Vertical)
                    size.x -= borderPadding.x;

                if (style != Style.Horizontal)
                    size.y -= borderPadding.y;
            }

            if (mTrans.localScale != size)
                mTrans.localScale = size;

            if (runOnlyOnce && Application.isPlaying) enabled = false;
        }
    }
}
